<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>噪声生成复杂的纹理-小试牛刀</title>
    <style>
        canvas{
            border:1px solid #ccc;
        }
    </style>
</head>
<body>
    <canvas width="554" height="554"></canvas>

    <script src="/common/lib/gl-renderer.js"></script>

    <script type="module">
        import { grayMatrix } from "/review/common/lib/utils.js"

        /**
         * 1.创建renderer对象
         * 2.创建webgl程序
         * 3.创建uniform变量
         * 4.将数据存入缓冲区
         * 5.渲染
         * */ 

        //  1.
        const canvas = document.querySelector("canvas");
        const renderer = new GlRenderer(canvas);

        (async function(){
            // 2.
            const vertex = `
                attribute vec2 a_vertexPosition;
                attribute vec2 uv;
                varying vec2 vUv;

                void main(){
                    vUv = uv;
                    gl_Position = vec4(a_vertexPosition, 1.0, 1.0);
                }
            `;
            const fragment = `
                #ifdef GL_ES
                    precision mediump float;
                #endif

                uniform float uTime;
                varying vec2 vUv;

                // 二维随机向量，值域范围（-1,1）
                vec2 random2(vec2 st){
                    st = vec2(
                            dot(st, vec2(127.1, 311.7)),
                            dot(st, vec2(269.5, 183.3))
                        );
                    return fract(sin(st) * 43758.5453123);
                }

                void main() {
                    vec2 st = vUv * 3.0;

                    vec3 color = vec3(.0);

                    vec2 fl = floor(st);
                    vec2 fr = fract(st);
                    // 生成随机特征点（距离中心点）
                    float md = 1.0;
                    vec2 mg, mr;

                    // 第一次遍历，找到特征点
                    for(int i = -1; i <= 1; i++){
                        // 计算坐标点到周围9个网格特征点的距离的最小值，并保存最小的那个特征点
                        for(int j = -1; j <= 1; j++){
                            vec2 g = vec2(float(i),float(j));
                            vec2 o = random2( fl + g );
                            o = 0.5 + 0.5 * sin( uTime + 6.2831 * o );
                            vec2 r = g + o - fr;

                            float m_dist = length(r);
                            if(md > m_dist){
                                // 保存最小距离时的偏移
                                mg = g;
                                // 保存特征点向量
                                mr = r;
                                // 保存最小距离
                                md = m_dist;
                            }
                        }
                    }

                    md = 1.0;
                    // 第二次遍历，计算出当前的像素点，与周围9个特征点，与距离最近的特征点之间的向量关系算法
                    for (int j= -1; j <= 1; j++) {
                        for (int i= -1; i <= 1; i++) {
                            // vec2 g = mg + vec2(float(i),float(j));
                            // 同上
                            vec2 g = vec2(float(i),float(j));
                            vec2 o = random2( fl + g );
                            o = 0.5 + 0.5 * sin( uTime + 6.2831 * o );
                            vec2 r = g + o - fr;
                            
                            // 0.00001是做精度处理
                            if ( dot(mr-r,mr-r) > 0.00001 ) {
                                // mr:最小距离的特征点到当前像素点的向量， r:周围特征点到当前像素点的向量。
                                // 这里的思路是：利用三角形外心计算
                                // 其余特征点到最小距离特征点形成向量a1 = r-mr， 像素点到a1中心点形成向量a2 = (mr+r)/2，
                                // 则求a2在a1上面的投影（点乘），就是距离场，求这个距离场的最小距离。
                                md = min(md, dot( 0.5 * (mr + r), normalize(r - mr) ));
                            }
                        }
                    }

                    // 等高线
                    // color = md * (0.5 + 0.5 * sin(64.0 * md)) * vec3(1.0);
                    color = md * fract(md * 35.0 / 2.0) * vec3(1.0);

                    // 边框线
                    color = mix( vec3(1.0), color, smoothstep( 0.01, 0.02, md ) );

                    // 标记特征点
                    color += step(length(mr), 0.03);

                    // 等高线
                    // float df = abs(sin(md * 30.0));
                    // float df = fract(md * 17.0 / 2.0); // 除以2才生效（可能是精度问题）
                    // color -= df;

                    gl_FragColor.rgb = color;
                    gl_FragColor.a = 1.0;
                }
            `;

            const program = renderer.compileSync(fragment,vertex);
            renderer.useProgram(program);

            // 3.
            renderer.uniforms.uTime = 0.0;
            // 4.
            renderer.setMeshData([{
                positions:[
                    [-1, -1],
                    [-1, 1],
                    [1, 1],
                    [1, -1],
                ],
                attributes:{
                    uv:[
                        [0, 0],
                        [0, 1],
                        [1, 1],
                        [1, 0],
                    ]
                },
                cells: [[0, 1, 2], [2, 0, 3]],
            }]);

            // 5.
            renderer.render();

            function update(t){
                renderer.uniforms.uTime = t * 0.001;
                requestAnimationFrame(update)
            }
            update(0)
        })();
        
    </script>
</body>
</html>